package kuzha.code.jvm;

import static org.objectweb.asm.Opcodes.BIPUSH;
import static org.objectweb.asm.Opcodes.DUP;
import static org.objectweb.asm.Opcodes.ICONST_0;
import static org.objectweb.asm.Opcodes.ICONST_1;
import static org.objectweb.asm.Opcodes.ICONST_2;
import static org.objectweb.asm.Opcodes.ICONST_3;
import static org.objectweb.asm.Opcodes.ICONST_4;
import static org.objectweb.asm.Opcodes.ICONST_5;
import static org.objectweb.asm.Opcodes.ICONST_M1;
import static org.objectweb.asm.Opcodes.INVOKESPECIAL;
import static org.objectweb.asm.Opcodes.INVOKESTATIC;
import static org.objectweb.asm.Opcodes.NEW;
import static org.objectweb.asm.Opcodes.SIPUSH;

import java.math.BigDecimal;
import java.math.BigInteger;

import org.objectweb.asm.MethodVisitor;

class CodeGenUtils {
	private CodeGenUtils(){}
	
	public static void emitIntValue(MethodVisitor mv, int value) {
		switch(value) {
			case -1:
				mv.visitInsn(ICONST_M1);
				break;
			case 0:
				mv.visitInsn(ICONST_0);
				break;
			case 1:
				mv.visitInsn(ICONST_1);
				break;
			case 2:
				mv.visitInsn(ICONST_2);
				break;
			case 3:
				mv.visitInsn(ICONST_3);
				break;
			case 4:
				mv.visitInsn(ICONST_4);
				break;
			case 5:
				mv.visitInsn(ICONST_5);
				break;
			default:
				if (Byte.MIN_VALUE <= value && value <= Byte.MAX_VALUE)
					mv.visitIntInsn(BIPUSH, value);
				else if (Short.MIN_VALUE <= value && value <= Short.MAX_VALUE)
					mv.visitIntInsn(SIPUSH, value);
				else
					mv.visitLdcInsn(value);
			break;
		}
	}
	public static void emitNumber(MethodVisitor mv, Number number) {
		if (number instanceof Integer) {
			emitIntValue(mv, number.intValue());
			mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
		}
		else if (number instanceof Long) {
			mv.visitLdcInsn(number.longValue());
			mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
		}
		else if (number instanceof Float) {
			mv.visitLdcInsn(number.floatValue());
			mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
		}
		else if (number instanceof Double) {
			mv.visitLdcInsn(number.doubleValue());
			mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
		}
		else if (number instanceof BigInteger) {
			BigInteger bigint = (BigInteger) number;
			mv.visitTypeInsn(NEW, "java/math/BigInteger");
			mv.visitInsn(DUP);
			mv.visitLdcInsn(bigint.toString());
			mv.visitMethodInsn(INVOKESPECIAL, "java/math/BigInteger", "<init>", "(Ljava/lang/String;)V");
		}
		else if (number instanceof BigDecimal) {
			BigDecimal bigdec = (BigDecimal) number;
			mv.visitTypeInsn(NEW, "java/math/BigInteger");
			mv.visitInsn(DUP);
			mv.visitLdcInsn(bigdec.toString());
			mv.visitMethodInsn(INVOKESPECIAL, "java/math/BigInteger", "<init>", "(Ljava/lang/String;)V");
		}
		else {
			throw new IllegalArgumentException("unknown number: " + number);
		}
	}
}
